using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Tanks.Common;
using Tanks.Model;
using System.Threading;

// Mercury Effects Library Imports
using ProjectMercury;
using ProjectMercury.Emitters;
using ProjectMercury.Modifiers;
using ProjectMercury.Renderers;
using System.Diagnostics;

/* 
 * ************************************************************************************
 * License: MIT Licence http://www.opensource.org/licenses/mit-license.php
 * Author: Juan Zamora 
 * Page: http://juanzamora.net
 * Game: Tanks - Based on the 2D Taks Game
 * Country: San Jose, Costa Rica - 2012
 * Special Thanks to: Riemers tutorial and all code samples there http://www.riemers.net
 * Mercury Particle Engine: http://mpe.codeplex.com
 * 
 * MIT License Terms
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * ************************************************************************************
 */

namespace Tanks
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        GraphicsDevice device;

        #region Game Variables
        // Textures
        Texture2D backgroundTexture;       // game background
        Texture2D foregroundTreeTextureA;  // Tree type 1
        Texture2D foregroundTreeTextureB;  // Tree type 2
        Texture2D foreground;              // Destroyable FG
        Texture2D tankTexture;             // the tank!
        Texture2D solidBlockTextureA;      // the solid non destroyable foreground
        Texture2D solidBlockTextureB;      // the solid non destroyable foreground
        Texture2D bulletTexture;           // Tank Shot Image
        Texture2D rocketTexture;           // Misile-Rocket Shot Image
        Texture2D floorDamagedTexture;     // Impact Zone

        // Screen Size
        int gameHeight = 800;
        int gameWidth = 800;

        // Will contain the list of squares painted in the grid
        CeramicType[,] paintedSquares;

        // logical size of the grid
        int gridSize = 100;

        // Percentage of GridSize to be covered by stones (10%)
        double solidCeramicsFactor = 0.10;

        // this factor will zoom in or out the game (GAME SCALE CONTROL VALUE)
        int cellFactor = 25; // 32px each square in the matrix

        // this will help avoding repainting foregorund if nothing has changed
        bool foregroundChanged = false;

        int playersCount = 2;
        // List of all players in the game
        Player[] players;
        // this is in function of Cellfactor
        float playerScale;
        float rocketScale;
        // Velocity Control
        float velocityControl = 3.0f;

        // Sound Effects
        SoundEffect loopSound;
        SoundEffectInstance loopSoundInstance;
        SoundEffect bangSound;
        SoundEffect tankDestroyedSound;
        SoundEffect grassCutSound;
        SoundEffect stoneHitSound;

        Color[,] bulletColorArray;
        Color[,] rocketColorArray;
        Color[,] tankColorArray;

        Color[,] fgTreeATextureColors;
        Color[,] fgTreeBTextureColors;
        Color[,] stoneATextureColors;
        Color[,] stoneBTextureColors;

        // Mercury Effects Objects
        Renderer mercuryRenderer;
        ParticleEffect grassParticles;
        ParticleEffect tankParticles;
        ParticleEffect rocketPowerParticles;

        #endregion

        #region XNA Game Methods

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            // Mercury Renderer Initialization
            mercuryRenderer = new SpriteBatchRenderer
            {
                GraphicsDeviceService = graphics
            };

            // Grass Particle Effect part of Mercury Lib
            grassParticles = new ParticleEffect();
            // rocket power particles
            rocketPowerParticles = new ParticleEffect();
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // Define Game Constraints
            graphics.PreferredBackBufferWidth = gameWidth;
            graphics.PreferredBackBufferHeight = gameHeight;
            graphics.IsFullScreen = false;
            graphics.ApplyChanges();
            Window.Title = "Tanker 2D - juanzamora.net";

            IsFixedTimeStep = true;
            //TargetElapsedTime = new TimeSpan(0, 0, 0, 0, 100);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            device = graphics.GraphicsDevice;

            // Load Textures
            backgroundTexture = Content.Load<Texture2D>("SAND");
            foregroundTreeTextureA = Content.Load<Texture2D>("TREE1");
            foregroundTreeTextureB = Content.Load<Texture2D>("TREE2");
            tankTexture = Content.Load<Texture2D>("TANK");
            solidBlockTextureA = Content.Load<Texture2D>("STONE1");
            solidBlockTextureB = Content.Load<Texture2D>("STONE2");
            bulletTexture = Content.Load<Texture2D>("BULLET");
            rocketTexture = Content.Load<Texture2D>("ROCKET");
            floorDamagedTexture = Content.Load<Texture2D>("DAMAGED");
            foreground = new Texture2D(device, 800, 800);

            // Mercury Effects Load
            grassParticles = Content.Load<ParticleEffect>("GRASS-PARTICLES");
            grassParticles.LoadContent(Content);
            grassParticles.Initialise();

            tankParticles = Content.Load<ParticleEffect>("TANK-PARTICLES");
            tankParticles.LoadContent(Content);
            tankParticles.Initialise();

            rocketPowerParticles = Content.Load<ParticleEffect>("ROCKET-POWER-PARTICLES");
            rocketPowerParticles.LoadContent(Content);
            rocketPowerParticles.Initialise();

            mercuryRenderer.LoadContent(Content);

            // Load Sounds
            loopSound = Content.Load<SoundEffect>("LOOP");
            bangSound = Content.Load<SoundEffect>("BANG");
            tankDestroyedSound = Content.Load<SoundEffect>("BOOM");
            grassCutSound = Content.Load<SoundEffect>("WHIP");
            stoneHitSound = Content.Load<SoundEffect>("SOLID");

            // Colission Color Arrays
            bulletColorArray = Helper.TextureTo2DArray(bulletTexture);
            rocketColorArray = Helper.TextureTo2DArray(rocketTexture);
            tankColorArray = Helper.TextureTo2DArray(tankTexture);

            // Loop BG Sound
            loopSoundInstance = loopSound.CreateInstance();
            loopSoundInstance.IsLooped = true;
            loopSoundInstance.Play();
            loopSoundInstance.Volume = 0.4f;

            // Create Players
            InitializePlayers();

            // Get Texture Color Information
            fgTreeATextureColors = Helper.TextureTo2DArray(foregroundTreeTextureA);
            fgTreeBTextureColors = Helper.TextureTo2DArray(foregroundTreeTextureB);

            // Generate Random Game Scenery
            GenerateRandomForeground();

            // Get All Textures Colors
            stoneATextureColors = Helper.TextureTo2DArray(solidBlockTextureA);
            stoneBTextureColors = Helper.TextureTo2DArray(solidBlockTextureB);

            // Create Foreground for first time use
            GenerateForeground();
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            ReadCommand();

            CheckEnemyBulletCollisions();

            CheckEnemyRocketCollisions();

            CheckSceneryCollissions();

            UpdateBullets(gameTime);

            UpdateRocket(gameTime);

            ParticlesUpdate(gameTime);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.WhiteSmoke);

            // Game Basic Elements
            spriteBatch.Begin();
            DrawGameScenery();
            DrawPlayers();
            spriteBatch.End();

            // Mercury Effects Display
            DrawEffects();

            base.Draw(gameTime);
        }
        #endregion

        #region Scenery Generation
        /// <summary>
        /// Random generation of the battle field
        /// </summary>
        void GenerateRandomForeground()
        {
            paintedSquares = new CeramicType[gridSize, gridSize];

            Random r = new Random();
            for (int i = 0; i < cellFactor; i++)
            {
                var j = r.Next(cellFactor);
                if (j != cellFactor - 1 && j != 0)
                    paintedSquares[i, j] = CeramicType.Stone;
            }

        }

        /// <summary>
        /// TODO: This is creating some delay on scenery reconstruction
        /// This method will paint the foreground according on how the paintedSquares array
        /// </summary>
        void GenerateForeground()
        {
            var s = new System.Diagnostics.Stopwatch();
            s.Start();

            foregroundChanged = false;
            int solidAmount = (int)(gridSize * solidCeramicsFactor);
            Color[] fgColors = new Color[gameWidth * gameHeight];
            float squareSide = gameHeight / cellFactor;

            // Ganerate Shaded Areas
            for (int i = 0; i < gameWidth; i++)
            {
                for (int j = 0; j < gameHeight; j++)
                {
                    var p = Helper.GetGameCoordinates(i, j, gameHeight, gameWidth, cellFactor);

                    switch (paintedSquares[p.X, p.Y])
                    {
                        case CeramicType.Grass:
                            fgColors[i + j * gameWidth] = ((p.X + p.Y) % 2 == 0) ?
                            fgTreeATextureColors[i % foregroundTreeTextureA.Width, j % foregroundTreeTextureA.Height] :
                            fgTreeBTextureColors[i % foregroundTreeTextureB.Width, j % foregroundTreeTextureB.Height];
                            break;
                        case CeramicType.Stone:
                            fgColors[i + j * gameWidth] = ((p.X + p.Y) % 2 == 0) ?
                                stoneATextureColors[i % solidBlockTextureA.Width, j % solidBlockTextureA.Height] :
                                                                                                                                                                                     stoneBTextureColors[i % solidBlockTextureB.Width, j % solidBlockTextureB.Height];
                            break;
                        case CeramicType.DamagedFloor:
                            fgColors[i + j * gameWidth] = Color.Transparent; // For the moment, floot damage will not be supported
                            break;
                        case CeramicType.None:
                            fgColors[i + j * gameWidth] = Color.Transparent;
                            break;
                        default:
                            fgColors[i + j * gameWidth] = Color.Transparent;
                            break;
                    }
                }
            }

            foreground = new Texture2D(device, gameWidth, gameHeight, false, SurfaceFormat.Color);
            foreground.SetData(fgColors);
        }

        /// <summary>
        /// Set the scenery on the whole screen
        /// </summary>
        void DrawGameScenery()
        {
            // create a rectangle at position xy (0,0) and size gameWidth, gameHeight  
            Rectangle screenRectangle = new Rectangle(0, 0, gameWidth, gameHeight);

            // this will draw the image within the rectangle constraint
            spriteBatch.Draw(backgroundTexture, screenRectangle, Color.White);
            spriteBatch.Draw(foreground, screenRectangle, Color.White);
        }

        /// <summary>
        /// Mercury Special FX Drawing
        /// </summary>
        void DrawEffects()
        {
            mercuryRenderer.RenderEffect(grassParticles);
            mercuryRenderer.RenderEffect(tankParticles);
            mercuryRenderer.RenderEffect(rocketPowerParticles);
        }
        #endregion

        #region User Interaction
        /// <summary>
        /// this method will help getting information for the players controllers (or keyboard)
        /// </summary>
        void ReadCommand()
        {
            KeyboardState k = Keyboard.GetState(); // TODO: Remove

            GamePadState state1 = GamePad.GetState(PlayerIndex.One);
            GamePadState state2 = GamePad.GetState(PlayerIndex.Two);

            // Allows the game to exit
            if (state1.Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // XBOX Controller Assigment            
            players[0].Controller = state1;
            players[1].Controller = state2;

            players[0].ControllerCoordinates = state1.ThumbSticks.Left;
            players[1].ControllerCoordinates = state2.ThumbSticks.Left;

            // Player Movement
            foreach (var player in players)
            {
                player.Cuadrant = new Vector2();
                player.Matrix = Matrix.CreateTranslation(player.ControllerCoordinates.X, -player.ControllerCoordinates.Y, 0);
                player.Direction = Vector2.Transform(player.Cuadrant, player.Matrix);

                var tankAngle = (float)Math.Atan2(player.Direction.X, -player.Direction.Y);

                // Avoids gamepad joystick to reset tank position
                if (player.Direction.X != 0 || player.Direction.Y != 0)
                {
                    player.Angle = tankAngle;
                    player.Position += player.Direction * velocityControl;
                }

                // FIRE BULLET
                if ((player.Controller.IsButtonDown(Buttons.A)) && !player.Bullet.IsFired)
                {
                    player.Bullet = new Bullet { Position = player.Position, Direction = player.Direction, IsFired = true };

                    if (player.Bullet.Direction.X != 0 || player.Bullet.Direction.Y != 0)
                        bangSound.Play();
                }

                // FIRE ROCKET
                if (player.Controller.IsButtonDown(Buttons.B) && !player.Rocket.IsFired)
                {
                    player.Rocket = new Rocket { Position = player.Position, Direction = player.Direction, IsFired = true, Angle = player.Angle };
                }
            }
        }

        /// <summary>
        /// Paint Tanks in game canvas
        /// </summary>
        void DrawPlayers()
        {
            foreach (var player in players)
            {
                if (player.IsAlive)
                {
                    // Tank Origin will be center of the tank
                    var origin = new Vector2(tankTexture.Width / 2, tankTexture.Width / 2);
                    spriteBatch.Draw(tankTexture, player.Position, null, player.Color, player.Angle, origin, playerScale, SpriteEffects.None, 1);

                    if (player.Bullet.IsFired)
                        spriteBatch.Draw(bulletTexture, player.Bullet.Position, null, player.Color, player.Bullet.Angle, new Vector2(bulletTexture.Width / 2, bulletTexture.Height / 2), playerScale, SpriteEffects.None, 1);

                    // TODO: FIX ROCKET ANGLE
                    if (player.Rocket.IsFired)
                        spriteBatch.Draw(rocketTexture, player.Rocket.Position, null, player.Color, player.Angle, new Vector2(42, 240), rocketScale, SpriteEffects.None, 1);
                }
            }
        }

        /// <summary>
        /// This method will set the players in their original position
        /// </summary>
        void InitializePlayers()
        {
            // Player Tank Colors
            Color[] playerColors = new Color[4]; // maximun 4 players (for each corner)
            playerColors[0] = Color.Red;
            playerColors[1] = Color.Green;
            playerColors[2] = Color.Blue;
            playerColors[3] = Color.Yellow;

            // Game for 2 players
            players = new Player[playersCount];

            // This will make the tank just a bit smaller for better handling... and for making the oponent harder to be hit!
            playerScale = (((gameHeight / cellFactor) * 0.65f) / (float)tankTexture.Height);
            rocketScale = (((gameHeight / cellFactor) * 0.8f) / (float)rocketTexture.Height);

            // Set all players information
            for (int i = 0; i < playersCount; i++)
            {
                players[i] = new Player();
                players[i].IsAlive = true;
                players[i].Color = playerColors[i];
                players[i].Angle = MathHelper.ToRadians(90);
                players[i].Bullet = new Bullet();
                players[i].Rocket = new Rocket();

                // Define Positon Accoring to Corner Assigned (left-up, right-up, left-down, right-down)
                switch (i)
                {
                    case 0: players[i].Position = Helper.GetInvertGameCoordinates(0, 0, gameHeight, gridSize, cellFactor, PlayerStartPosition.Centered); break;
                    case 2: players[i].Position = Helper.GetInvertGameCoordinates(cellFactor - 1, cellFactor - 1, gameHeight, gridSize, cellFactor, PlayerStartPosition.Centered); break;
                    case 3: players[i].Position = Helper.GetInvertGameCoordinates(cellFactor - 1, 0, gameHeight, gridSize, cellFactor, PlayerStartPosition.Centered); break;
                    case 1: players[i].Position = Helper.GetInvertGameCoordinates(0, cellFactor - 1, gameHeight, gridSize, cellFactor, PlayerStartPosition.Centered); break;
                }

            }

        }

        /// <summary>
        /// This will make the bullet to move
        /// </summary>
        void UpdateBullets(GameTime gameTime)
        {
            foreach (var player in players)
            {
                var elapsed = gameTime.ElapsedGameTime.Milliseconds;

                if (player.IsAlive && player.Bullet.IsFired)
                {
                    // 4.5x velocity from tank speed
                    if (player.Bullet.Direction.X != 0 || player.Bullet.Direction.Y != 0)
                    {
                        player.Bullet.Position += player.Bullet.Direction * velocityControl * 2;
                    }
                    else
                        player.Bullet.IsFired = false;
                }

                if (Helper.IsOutOfScreen(player.Bullet.Position, gameHeight, gameWidth) && player.Bullet.IsFired)
                {
                    player.Bullet.IsFired = false;
                }
            }

        }

        /// <summary>
        /// Rocket movement control
        /// </summary>
        void UpdateRocket(GameTime gameTime)
        {
            foreach (var player in players)
            {
                if (player.IsAlive && player.Rocket.IsFired)
                {
                    // 4.5x velocity from tank speed
                    if (player.Rocket.Direction.X != 0 || player.Rocket.Direction.Y != 0)
                    {
                        // this will incrementally add speed of the rocket 
                        player.Rocket.Direction += new Vector2(player.Rocket.Direction.X, player.Rocket.Direction.Y) / 75f;
                        player.Rocket.Position += player.Rocket.Direction + new Vector2(player.Controller.ThumbSticks.Right.X, -player.Controller.ThumbSticks.Right.Y);
                        player.Rocket.Angle = (float)Math.Atan2(player.Rocket.Position.X, -player.Rocket.Position.Y);

                        // particles Trigger
                        rocketPowerParticles.Trigger(player.Rocket.Position);
                    }
                    else
                        player.Rocket.IsFired = false;
                }

                if (Helper.IsOutOfScreen(player.Rocket.Position, gameHeight, gameWidth) && player.Rocket.IsFired)
                {
                    player.Rocket.IsFired = false;
                }
            }

        }

        /// <summary>
        /// This will update particles for the Mercury Effects Library
        /// </summary>
        /// <param name="gameTime"></param>
        void ParticlesUpdate(GameTime gameTime)
        {
            // Bullet Grass Effect Update
            float timeElapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            grassParticles.Update(timeElapsed);
            tankParticles.Update(timeElapsed);
            rocketPowerParticles.Update(timeElapsed);
        }
        #endregion

        #region Game Collissions

        /// <summary>
        /// This checks if a bullet fired is has reached another player!
        /// Let the party begin...
        /// </summary>
        private void CheckEnemyBulletCollisions()
        {
            foreach (var player in players)
            {
                Matrix playerMatrix = Matrix.CreateTranslation(8, 8, 0) * Matrix.CreateScale(playerScale) * Matrix.CreateTranslation(player.Position.X, player.Position.Y, 0);

                var p = Helper.GetGameCoordinates((int)player.Bullet.Position.X, (int)player.Bullet.Position.Y, gameHeight, gameWidth, cellFactor);

                if (!Helper.IsOutOfScreen(player.Bullet.Position, gameHeight, gameWidth))
                {
                    // Destroy Grass and Replace with nothing
                    if (paintedSquares[p.X, p.Y] == CeramicType.Grass)
                    {
                        // Display Grass Cut Particles Effect from Mercury
                        grassParticles.Trigger(player.Bullet.Position);

                        paintedSquares[p.X, p.Y] = CeramicType.None;
                        player.Bullet.IsFired = false;
                        grassCutSound.Play();
                        // foregroundChanged = true;
                    }
                    else
                    {
                        // Stop Bullet.
                        if (paintedSquares[p.X, p.Y] == CeramicType.Stone)
                            player.Bullet.IsFired = false;
                    }
                }
                else
                {
                    player.Bullet.IsFired = false;
                }

                foreach (var enemy in players)
                {
                    if (player.IsAlive && enemy.Bullet.IsFired && player != enemy)
                    {
                        var enemyBulletMatrix = Matrix.CreateTranslation(8, 8, 0) * Matrix.CreateScale(playerScale) * Matrix.CreateTranslation(enemy.Bullet.Position.X, enemy.Bullet.Position.Y, 0);
                        var playerBulletCollission = Helper.TexturesCollide(bulletColorArray, enemyBulletMatrix, tankColorArray, playerMatrix);

                        if (playerBulletCollission.X > -1)
                        {
                            // Bullet has reached the tank...
                            player.IsAlive = false; // You are toasted!
                            player.Bullet.IsFired = false;
                            enemy.Bullet.IsFired = false;

                            // Display Grass Cut Particles Effect from Mercury
                            tankParticles.Trigger(playerBulletCollission);

                            // EXPLOSION SOUND EFFECT!
                            tankDestroyedSound.Play();
                        }
                    }
                }
            }
        }

        private void CheckEnemyRocketCollisions()
        {
            foreach (var player in players)
            {
                Matrix playerMatrix = Matrix.CreateTranslation(8, 8, 0) * Matrix.CreateScale(playerScale) * Matrix.CreateTranslation(player.Position.X, player.Position.Y, 0);

                var p = Helper.GetGameCoordinates((int)player.Rocket.Position.X, (int)player.Rocket.Position.Y, gameHeight, gameWidth, cellFactor);

                // Validate Rocket out of bounds
                if (Helper.IsOutOfScreen(player.Rocket.Position, gameHeight, gameWidth))
                {
                    player.Rocket.IsFired = false;
                }

                foreach (var enemy in players)
                {
                    if (player.IsAlive && enemy.Rocket.IsFired && player != enemy)
                    {
                        var enemyRocketMatrix = Matrix.CreateTranslation(8, 8, 0) * Matrix.CreateScale(rocketScale) * Matrix.CreateTranslation(enemy.Rocket.Position.X, enemy.Rocket.Position.Y, 0);
                        var playerRocketCollission = Helper.TexturesCollide(rocketColorArray, enemyRocketMatrix, tankColorArray, playerMatrix);

                        if (playerRocketCollission.X > -1)
                        {
                            // Bullet has reached the tank...
                            player.IsAlive = false; // You are toasted!
                            player.Rocket.IsFired = false;
                            enemy.Rocket.IsFired = false;

                            // Display Grass Cut Particles Effect from Mercury
                            tankParticles.Trigger(playerRocketCollission);

                            // EXPLOSION SOUND EFFECT!
                            tankDestroyedSound.Play();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Each tank should not:
        /// - leave game boundary
        /// - Overlap Grass or Stone
        /// </summary>
        private void CheckSceneryCollissions()
        {
            foreach (var player in players)
            {
                if (!Helper.IsOutOfScreen(player.Position, gameWidth, gameWidth))
                {
                    var gamePositioning = Helper.GetGameCoordinates((int)player.Position.X, (int)player.Position.Y, gameHeight, gameWidth, cellFactor);
                    var ceramic = paintedSquares[gamePositioning.X, gamePositioning.Y];

                    // will only advance to next position if there is no scenery like grass or rocks
                    if (ceramic != CeramicType.None && ceramic != CeramicType.DamagedFloor)
                    {
                        // Foregorund Colission
                        // this returns object to the position before the collission...
                        player.Position -= player.Direction * velocityControl;
                        player.Angle *= (float)Math.PI; // workaround to avoid bouncing.
                    }
                }
                else
                {
                    // Game Edge Colission
                    player.Position -= player.Direction * velocityControl;
                }
            }

        }
        #endregion
    }
}
